import { isArray } from '@/utils/type'

/**
 * @description: 观察DOM元素变化
 * @param {HTMLElement | Ref} target
 * @param {function} callback DOM元素变化时的回调函数
 * @param {object} options DOM元素变化时的回调函数
 *  subtree: 是否监听以 target 为根节点的整个子树，包括子树中所有节点的属性
 *  childList: 是否监听 target 节点中发生的节点的新增与删除
 *  attributes: 是否观察所有监听的节点属性值的变化
 *  attributeFilter: 声明哪些属性名会被监听的数组；如果不声明该属性，所有属性的变化都将触发通知
 */
export default function useMutationObserver(target, callback, options) {
  const stopObservation = ref(false)
  let observer = undefined

  const targets = computed(() => {
    const targetsValue = toValue(target)
    if (targetsValue) {
      if (isArray(targetsValue)) {
        return targetsValue.map((el) => toValue(el)).filter((el) => el)
      } else {
        return [targetsValue]
      }
    }
    return []
  })

  watch(
    () => targets.value,
    () => {
      cleanObserver()
      initObserverElement()
    },
    {
      immediate: true,
      flush: 'post',
    },
  )

  onBeforeUnmount(() => cleanObserver())

  // 初始化 ResizeObserver，观察目标元素
  function initObserverElement() {
    if (targets.value.length && !stopObservation.value) {
      observer = new ResizeObserver(callback)
      targets.value.forEach((el) => observer.observe(el, options))
    }
  }

  // 断开ResizeObserver连接
  function cleanObserver() {
    if (observer) {
      observer.disconnect()
      observer = undefined
    }
  }

  function stop() {
    stopObservation.value = true
    cleanObserver()
  }

  function start() {
    stopObservation.value = false
    initObserverElement()
  }

  return {
    stopObservation,
    stop,
    start,
  }
}
